home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Format CD 22
/
Amiga Format AFCD22 (Jan 1998, Issue 106).iso
/
-in_the_mag-
/
converters
/
graphics
/
netpbm
/
source1
/
pbm
/
pktopbm.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-11-16
|
10KB
|
339 lines
/*
pktopbm, adapted from "pktopx in C by Tomas Rokicki" by AJCD 1/8/90
compile with: cc -lpbm -o pktopbm pktopbm.c
*/
#include <stdio.h>
#include "pbm.h"
#define NAMELENGTH 80
#define MAXROWWIDTH 3200
#define MAXPKCHAR 256
typedef int integer ;
typedef unsigned char quarterword ;
typedef char boolean ;
typedef quarterword eightbits ;
static FILE *pkfile ;
static char pkname[NAMELENGTH+1] ;
static integer pktopbm_pkloc = 0;
static char *filename[MAXPKCHAR] ;
static bit **bitmap = NULL ;
static integer dynf ;
static eightbits inputbyte ;
static eightbits bitweight ;
static integer repeatcount ;
static integer flagbyte ;
/* add a suffix to a filename in an allocated space */
static void
pktopbm_add_suffix(name, suffix)
char *name, *suffix ;
{
char *slash = rindex(name, '/');
char *dot = rindex(name, '.');
if ((dot && slash ? dot < slash : !dot) && strcmp(name, "-"))
strcat(name, suffix);
}
/* get a byte from the PK file */
static eightbits pktopbm_pkbyte()
{
pktopbm_pkloc++ ;
return(getc(pkfile)) ;
}
/* get a 16-bit half word from the PK file */
static integer get16()
{
integer a = pktopbm_pkbyte() ;
return((a<<8) + pktopbm_pkbyte()) ;
}
/* get a 32-bit word from the PK file */
static integer get32()
{
integer a = get16() ;
if (a > 32767) a -= 65536 ;
return((a<<16) + get16()) ;
}
/* get a nibble from current input byte, or new byte if no current byte */
static integer getnyb()
{
eightbits temp ;
if (bitweight == 0) {
inputbyte = pktopbm_pkbyte() ;
bitweight = 16 ;
}
temp = inputbyte / bitweight ;
inputbyte -= temp * bitweight ;
bitweight >>= 4 ;
return(temp) ;
}
/* get a bit from the current input byte, or a new byte if no current byte */
static boolean getbit()
{
boolean temp ;
bitweight >>= 1 ;
if (bitweight == 0) {
inputbyte = pktopbm_pkbyte() ;
bitweight = 128 ;
}
temp = (inputbyte >= bitweight) ;
if (temp) inputbyte -= bitweight ;
return(temp) ;
}
/* unpack a dynamically packed number. dynf is dynamic packing threshold */
static integer pkpackednum()
{
integer i, j ;
i = getnyb() ;
if (i == 0) { /* large run count, >= 3 nibbles */
do {
j = getnyb() ; /* count extra nibbles */
i++ ;
} while (j == 0) ;
while (i > 0) {
j = (j<<4) + getnyb() ; /* add extra nibbles */
i-- ;
}
return (j - 15 +((13 - dynf)<<4) + dynf) ;
} else if (i <= dynf) return (i) ; /* number > 0 and <= dynf */
else if (i < 14) return (((i - dynf - 1)<<4) + getnyb() + dynf + 1) ;
else {
if (i == 14) repeatcount = pkpackednum() ; /* get repeat count */
else repeatcount = 1 ; /* value 15 indicates repeat count 1 */
return(pkpackednum()) ;
}
}
/* skip specials in PK files, inserted by Metafont or some other program */
static void
skipspecials()
{
integer i, j;
do {
flagbyte = pktopbm_pkbyte() ;
if (flagbyte >= 240)
switch(flagbyte) {
case 240: /* specials of size 1-4 bytes */
case 241:
case 242:
case 243:
i = 0 ;
for (j = 240 ; j <= flagbyte ; j ++) i = (i<<8) + pktopbm_pkbyte() ;
for (j = 1 ; j <= i ; j ++) pktopbm_pkbyte() ; /* ignore special */
break ;
case 244: /* no-op, parameters to specials */
get32() ;
case 245: /* start of postamble */
case 246: /* no-op */
break ;
case 247: /* pre-amble in wrong place */
case 248:
case 249:
case 250:
case 251:
case 252:
case 253:
case 254:
case 255:
pm_error("unexpected flag byte %d", flagbyte) ;
}
} while (!(flagbyte < 240 || flagbyte == 245)) ;
}
/* ignore character packet */
static void
ignorechar(car, endofpacket)
integer car, endofpacket;
{
while (pktopbm_pkloc != endofpacket) pktopbm_pkbyte() ;
if (car < 0 || car >= MAXPKCHAR)
pm_message("Character %d out of range", car) ;
skipspecials() ;
}
int
main(argc, argv)
int argc ;
char *argv[] ;
{
integer endofpacket ;
boolean turnon ;
integer i, j;
integer car ;
bit row[MAXROWWIDTH+1] ;
char *usage = "pkfile[.pk] [[-c num] pbmfile]...";
pbm_init(&argc, argv);
for (i = 0 ; i < MAXPKCHAR ; i ++) filename[i] = NULL ;
pm_message("This is PKtoPBM, version 2.4") ;
if (--argc < 1) pm_usage(usage) ;
strcpy(pkname, *++argv) ;
pktopbm_add_suffix(pkname, ".pk") ;
car = 0 ;
while (++argv, --argc) {
if (argv[0][0] == '-' && argv[0][1])
switch (argv[0][1]) {
case 'C':
case 'c':
if (argv[0][2]) car = atoi(*argv+2) ;
else if (++argv, --argc) car = atoi(*argv) ;
else pm_usage(usage) ;
break ;
default:
pm_usage(usage) ;
} else if (car < 0 || car >= MAXPKCHAR) {
pm_error("character must be in range 0 to %d (-c)", MAXPKCHAR-1) ;
} else filename[car++] = *argv ;
}
pkfile = pm_openr(pkname);
if (pktopbm_pkbyte() != 247)
pm_error("bad PK file (pre command missing)") ;
if (pktopbm_pkbyte() != 89)
pm_error("wrong version of packed file") ;
j = pktopbm_pkbyte() ; /* get header comment size */
for (i = 1 ; i <= j ; i ++) pktopbm_pkbyte() ; /* ignore header comment */
get32() ; /* ignore designsize */
get32() ; /* ignore checksum */
if (get32() != get32()) /* h & v pixels per point */
pm_message("Warning: aspect ratio not 1:1") ;
skipspecials() ;
while (flagbyte != 245) { /* not at postamble */
integer cheight, cwidth ;
FILE *ofp;
dynf = (flagbyte>>4) ; /* get dynamic packing value */
flagbyte &= 15 ;
turnon = (flagbyte >= 8) ; /* black or white initially? */
if (turnon) flagbyte &= 7 ; /* long or short form */
if (flagbyte == 7) { /* long form preamble */
integer packetlength = get32() ; /* character packet length */
car = get32() ; /* character number */
endofpacket = packetlength + pktopbm_pkloc ; /* calculate end of packet */
if (car >= MAXPKCHAR || car < 0) {
ignorechar(car, endofpacket);
continue;
}
get32() ; /* ignore tfmwidth */
get32() ; /* ignore horiz escapement */
get32() ; /* ignore vert escapement */
cwidth = get32() ; /* bounding box width */
cheight = get32() ; /* bounding box height */
if (cwidth < 0 || cheight < 0 || cwidth > 65535 || cheight > 65535) {
ignorechar(car, endofpacket);
continue;
}
get32() ; /* ignore horiz offset */
get32() ; /* ignore vert offset */
} else if (flagbyte > 3) { /* extended short form */
integer packetlength = ((flagbyte - 4)<<16) + get16() ;
/* packet length */
car = pktopbm_pkbyte() ; /* char number */
endofpacket = packetlength + pktopbm_pkloc ; /* calculate end of packet */
if (car >= MAXPKCHAR) {
ignorechar(car, endofpacket);
continue;
}
pktopbm_pkbyte() ; /* ignore tfmwidth (3 bytes) */
get16() ; /* ignore tfmwidth (3 bytes) */
get16() ; /* ignore horiz escapement */
cwidth = get16() ; /* bounding box width */
cheight = get16() ; /* bounding box height */
get16() ; /* ignore horiz offset */
get16() ; /* ignore vert offset */
} else { /* short form preamble */
integer packetlength = (flagbyte<<8) + pktopbm_pkbyte() ;
/* packet length */
car = pktopbm_pkbyte() ; /* char number */
endofpacket = packetlength + pktopbm_pkloc ; /* calculate end of packet */
if (car >= MAXPKCHAR) {
ignorechar(car, endofpacket);
continue;
}
pktopbm_pkbyte() ; /* ignore tfmwidth (3 bytes) */
get16() ; /* ignore tfmwidth (3 bytes) */
pktopbm_pkbyte() ; /* ignore horiz escapement */
cwidth = pktopbm_pkbyte() ; /* bounding box width */
cheight = pktopbm_pkbyte() ; /* bounding box height */
pktopbm_pkbyte() ; /* ignore horiz offset */
pktopbm_pkbyte() ; /* ignore vert offset */
}
if (filename[car]) {
bitmap = pbm_allocarray(cwidth, cheight) ;
if (bitmap == NULL)
pm_error("out of memory allocating bitmap") ;
} else {
ignorechar(car, endofpacket);
continue;
}
bitweight = 0 ;
if (dynf == 14) { /* bitmapped character */
for (i = 0 ; i < cheight ; i ++)
for (j = 0 ; j < cwidth ; j ++) {
if (getbit())
bitmap[i][j] = PBM_BLACK ;
else
bitmap[i][j] = PBM_WHITE ;
}
} else { /* dynamically packed char */
integer rowsleft = cheight ;
integer hbit = cwidth ;
integer rp = 0;
repeatcount = 0 ;
while (rowsleft > 0) {
integer count = pkpackednum() ; /* get current colour count */
while (count > 0) {
if (count < hbit) { /* doesn't extend past row */
hbit -= count ;
while (count--)
row[rp++] = turnon ? PBM_BLACK : PBM_WHITE;
} else { /* reaches end of row */
count -= hbit ;
while (hbit--)
row[rp++] = turnon ? PBM_BLACK : PBM_WHITE;
for (i = 0; i <= repeatcount; i++) /* fill row */
for (j = 0; j < cwidth; j++)
bitmap[i + cheight-rowsleft][j] = row[j] ;
rowsleft -= repeatcount + 1;
repeatcount = rp = 0 ;
hbit = cwidth ;
}
}
turnon = !turnon ;
}
if (rowsleft != 0 || hbit != cwidth)
pm_error("bad pk file (more bits than required)") ;
}
if (endofpacket != pktopbm_pkloc)
pm_error("bad pk file (bad packet length)") ;
ofp = pm_openw(filename[car]);
filename[car] = NULL;
pbm_writepbm(ofp, bitmap, cwidth, cheight, 0) ;
pbm_freearray(bitmap, cheight) ;
pm_close(ofp) ;
skipspecials() ;
}
while (! feof(pkfile)) pktopbm_pkbyte() ; /* skip trailing junk */
pm_close(pkfile);
for (car = 0; car < MAXPKCHAR; car++)
if (filename[car])
pm_message("Warning: No character in position %d (file %s).",
car, filename[car]) ;
pm_message("%d bytes read from packed file.", pktopbm_pkloc-1) ;
exit(0);
}